/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hop.databases.sapdb;

import org.apache.hop.core.Const;
import org.apache.hop.core.database.BaseDatabaseMeta;
import org.apache.hop.core.database.DatabaseMeta;
import org.apache.hop.core.database.DatabaseMetaPlugin;
import org.apache.hop.core.database.IDatabase;
import org.apache.hop.core.gui.plugin.GuiPlugin;
import org.apache.hop.core.row.IValueMeta;

/**
 * Contains SAP DB specific information through static final members
 */
@DatabaseMetaPlugin(type = "SAPDB", typeDescription = "MaxDB (SAP DB)", documentationUrl = "/database/databases/sapdb.html")
@GuiPlugin(id = "GUI-SAPDBDatabaseMeta")
public class SAPDBDatabaseMeta extends BaseDatabaseMeta implements IDatabase {
  @Override
  public int[] getAccessTypeList() {
    return new int[] {DatabaseMeta.TYPE_ACCESS_NATIVE};
  }

  @Override
  public int getDefaultDatabasePort() {
    return -1;
  }

  /** @return Whether or not the database can use auto increment type of fields (pk) */
  @Override
  public boolean supportsAutoInc() {
    return false;
  }

  @Override
  public String getDriverClass() {
    return "com.sap.dbtech.jdbc.DriverSapDB";
  }

  @Override
  public String getURL(String hostname, String port, String databaseName) {
    return "jdbc:sapdb://" + hostname + "/" + databaseName;
  }

  /** @return true if the database supports bitmap indexes */
  @Override
  public boolean supportsBitmapIndex() {
    return false;
  }

  /** @return true if the database supports synonyms */
  @Override
  public boolean supportsSynonyms() {
    return false;
  }

  /**
   * Generates the SQL statement to add a column to the specified table
   *
   * @param tableName The table to add
   * @param v The column defined as a value
   * @param tk the name of the technical key field
   * @param useAutoinc whether or not this field uses auto increment
   * @param pk the name of the primary key field
   * @param semicolon whether or not to add a semi-colon behind the statement.
   * @return the SQL statement to add a column to the specified table
   */
  @Override
  public String getAddColumnStatement(
      String tableName, IValueMeta v, String tk, boolean useAutoinc, String pk, boolean semicolon) {
    return "ALTER TABLE "
        + tableName
        + " ADD "
        + getFieldDefinition(v, tk, pk, useAutoinc, true, false);
  }

  /**
   * Generates the SQL statement to modify a column in the specified table
   *
   * @param tableName The table to add
   * @param v The column defined as a value
   * @param tk the name of the technical key field
   * @param useAutoinc whether or not this field uses auto increment
   * @param pk the name of the primary key field
   * @param semicolon whether or not to add a semi-colon behind the statement.
   * @return the SQL statement to modify a column in the specified table
   */
  @Override
  public String getModifyColumnStatement(
      String tableName, IValueMeta v, String tk, boolean useAutoinc, String pk, boolean semicolon) {
    return "ALTER TABLE "
        + tableName
        + " ALTER COLUMN "
        + v.getName()
        + " TYPE "
        + getFieldDefinition(v, tk, pk, useAutoinc, false, false);
  }

  @Override
  public String getFieldDefinition(
      IValueMeta v, String tk, String pk, boolean useAutoinc, boolean addFieldName, boolean addCr) {
    String retval = "";

    String fieldname = v.getName();
    int length = v.getLength();
    int precision = v.getPrecision();

    if (addFieldName) {
      if (Const.indexOfString(fieldname, getReservedWords()) >= 0) {
        retval += getStartQuote() + fieldname + getEndQuote();
      } else {
        retval += fieldname + " ";
      }
    }

    int type = v.getType();
    switch (type) {
      case IValueMeta.TYPE_TIMESTAMP:
      case IValueMeta.TYPE_DATE:
        retval += "TIMESTAMP";
        break;
      case IValueMeta.TYPE_BOOLEAN:
        retval += "CHAR(1)";
        break;
      case IValueMeta.TYPE_NUMBER:
      case IValueMeta.TYPE_INTEGER:
      case IValueMeta.TYPE_BIGNUMBER:
        if (fieldname.equalsIgnoreCase(tk)
            || // Technical key
            fieldname.equalsIgnoreCase(pk) // Primary key
        ) {
          retval += "BIGINT NOT NULL PRIMARY KEY";
        } else {
          if (length > 0) {
            if (precision > 0 || length > 18) {
              retval += "DECIMAL(" + length;
              if (precision > 0) {
                retval += ", " + precision;
              }
              retval += ")";
            } else {
              if (length > 9) {
                retval += "INT64";
              } else {
                if (length < 5) {
                  retval += "SMALLINT";
                } else {
                  retval += "INTEGER";
                }
              }
            }

          } else {
            retval += "DOUBLE";
          }
        }
        break;
      case IValueMeta.TYPE_STRING:
        if (length < 32720) {
          retval += "VARCHAR";
          if (length > 0) {
            retval += "(" + length + ")";
          } else {
            retval += "(8000)"; // Maybe use some default DB String length?
          }
        } else {
          retval += "BLOB SUB_TYPE TEXT";
        }
        break;
      default:
        retval += " UNKNOWN";
        break;
    }

    if (addCr) {
      retval += Const.CR;
    }

    return retval;
  }

  @Override
  public String[] getReservedWords() {
    return new String[] {
      "ABS",
      "ABSOLUTE",
      "ACOS",
      "ADDDATE",
      "ADDTIME",
      "ALL",
      "ALPHA",
      "ALTER",
      "ANY",
      "ASCII",
      "ASIN",
      "ATAN",
      "ATAN2",
      "AVG",
      "BINARY",
      "BIT",
      "BOOLEAN",
      "BYTE",
      "CASE",
      "CEIL",
      "CEILING",
      "CHAR",
      "CHARACTER",
      "CHECK",
      "CHR",
      "COLUMN",
      "CONCAT",
      "CONSTRAINT",
      "COS",
      "COSH",
      "COT",
      "COUNT",
      "CROSS",
      "CURDATE",
      "CURRENT",
      "CURTIME",
      "DATABASE",
      "DATE",
      "DATEDIFF",
      "DAY",
      "DAYNAME",
      "DAYOFMONTH",
      "DAYOFWEEK",
      "DAYOFYEAR",
      "DEC",
      "DECIMAL",
      "DECODE",
      "DEFAULT",
      "DEGREES",
      "DELETE",
      "DIGITS",
      "DISTINCT",
      "DOUBLE",
      "EXCEPT",
      "EXISTS",
      "EXP",
      "EXPAND",
      "FIRST",
      "FIXED",
      "FLOAT",
      "FLOOR",
      "FOR",
      "FROM",
      "FULL",
      "GET_OBJECTNAME",
      "GET_SCHEMA",
      "GRAPHIC",
      "GREATEST",
      "GROUP",
      "HAVING",
      "HEX",
      "HEXTORAW",
      "HOUR",
      "IFNULL",
      "IGNORE",
      "INDEX",
      "INITCAP",
      "INNER",
      "INSERT",
      "INT",
      "INTEGER",
      "INTERNAL",
      "INTERSECT",
      "INTO",
      "JOIN",
      "KEY",
      "LAST",
      "LCASE",
      "LEAST",
      "LEFT",
      "LENGTH",
      "LFILL",
      "LIST",
      "LN",
      "LOCATE",
      "LOG",
      "LOG10",
      "LONG",
      "LONGFILE",
      "LOWER",
      "LPAD",
      "LTRIM",
      "MAKEDATE",
      "MAKETIME",
      "MAPCHAR",
      "MAX",
      "MBCS",
      "MICROSECOND",
      "MIN",
      "MINUTE",
      "MOD",
      "MONTH",
      "MONTHNAME",
      "NATURAL",
      "NCHAR",
      "NEXT",
      "NO",
      "NOROUND",
      "NOT",
      "NOW",
      "NULL",
      "NUM",
      "NUMERIC",
      "OBJECT",
      "OF",
      "ON",
      "ORDER",
      "PACKED",
      "PI",
      "POWER",
      "PREV",
      "PRIMARY",
      "RADIANS",
      "REAL",
      "REJECT",
      "RELATIVE",
      "REPLACE",
      "RFILL",
      "RIGHT",
      "ROUND",
      "ROWID",
      "ROWNO",
      "RPAD",
      "RTRIM",
      "SECOND",
      "SELECT",
      "SELUPD",
      "SERIAL",
      "SET",
      "SHOW",
      "SIGN",
      "SIN",
      "SINH",
      "SMALLINT",
      "SOME",
      "SOUNDEX",
      "SPACE",
      "SQRT",
      "STAMP",
      "STATISTICS",
      "STDDEV",
      "SUBDATE",
      "SUBSTR",
      "SUBSTRING",
      "SUBTIME",
      "SUM",
      "SYSDBA",
      "TABLE",
      "TAN",
      "TANH",
      "TIME",
      "TIMEDIFF",
      "TIMESTAMP",
      "TIMEZONE",
      "TO",
      "TOIDENTIFIER",
      "TRANSACTION",
      "TRANSLATE",
      "TRIM",
      "TRUNC",
      "TRUNCATE",
      "UCASE",
      "UID",
      "UNICODE",
      "UNION",
      "UPDATE",
      "UPPER",
      "USER",
      "USERGROUP",
      "USING",
      "UTCDATE",
      "UTCDIFF",
      "VALUE",
      "VALUES",
      "VARCHAR",
      "VARGRAPHIC",
      "VARIANCE",
      "WEEK",
      "WEEKOFYEAR",
      "WHEN",
      "WHERE",
      "WITH",
      "YEAR",
      "ZONED"
    };
  }
}
